// FeedFetcher.cpp: implementation of the FeedFetcher class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "tinypp.h"
#include "FeedFetcher.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
FeedFetcher* FeedFetcher::pInstance = NULL;
const char* FeedFetcher::strAgentName = "TinyPP/0.1:jzhang533@gmail.com";
class AutoFeedFetcherCloser
{
public:
	AutoFeedFetcherCloser(){};
	~AutoFeedFetcherCloser(){
		if(FeedFetcher::pInstance){
			delete FeedFetcher::pInstance;
			FeedFetcher::pInstance=NULL;
		}
	}	
};

AutoFeedFetcherCloser g_autoFeedFetcherCloser;

FeedFetcher* FeedFetcher::Instance(){
		if (!pInstance) {
			pInstance = new FeedFetcher;
			pInstance->CreateWorkerThread();
		}
		return pInstance;
	};



FetchProgressHandler g_FPHDefault;
FeedFetcher::FeedFetcher():m_pWorkerThread(NULL),m_bRunning(true),m_FPH(&g_FPHDefault){
		InitializeCriticalSection(&m_cs);
}

FeedFetcher::~FeedFetcher()
{
	DeleteCriticalSection(&m_cs);
}
bool FeedFetcher::FetchAGroup(FeedGroup* pGroup)
{
	return FetchAGroup(pGroup->m_nFeedGroupID);
}


bool FeedFetcher::FetchAGroup(int nID)
{
	vector<int> Children;
	int i=0;

	DBManager::Instance()->GetChildrenFeeds(nID,Children);	
	for(i=0; i<Children.size();i++)
		FetchAFeed(Children[i]);
	DBManager::Instance()->GetChildrenGroups(nID,Children);
	for(i=0; i<Children.size();i++)
		FetchAGroup(Children[i]);

	return true;
}


bool FeedFetcher::FetchAFeed(int nID)
{
	EnterCriticalSection(&m_cs);
	m_ToFetchFeeds.push(nID);
	LeaveCriticalSection(&m_cs);
	
	return true;
}

void FeedFetcher::StopFetching()
{
	EnterCriticalSection(&m_cs);
	while (!m_ToFetchFeeds.empty()) {
		m_ToFetchFeeds.pop();
	}	
	LeaveCriticalSection(&m_cs);
}


bool FeedFetcher::RunFetchAFeed(int nID)
{
	string strUrl;
	if( ! DBManager::Instance()->GetFeedUrl(nID,strUrl) )
		return false;

	if (!m_grabber.GetFile(strUrl.c_str(), _T("temp.xml"),strAgentName) != S_OK ){
			return false;
    }


	RSSParser parser;
	RSSFeed Feed;
	if(!parser.ParseFile("temp.xml",&Feed))
	{
		m_FPH->OnFinishFetchAFeed(nID,0);
		return false;
	}
	
	vector<RSSItem> *items=Feed.GetItems();	
	bool bRet = DBManager::Instance()->InsetItems(nID,items);
	m_FPH->OnFinishFetchAFeed(nID,items->size());
	return bRet;
}


bool FeedFetcher::FetchAFeed(RSSFeed* pFeed)
{
	return FetchAFeed(pFeed->m_nFeedID);
}

bool FeedFetcher::CreateWorkerThread()
{
	m_pWorkerThread = AfxBeginThread (FeedFetcher::ThreadProc, 0);		
	return m_pWorkerThread != NULL;
}

UINT FeedFetcher::ThreadProc(LPVOID pParam )
{
	FeedFetcher::Instance()->WorkerThreadProc();
	return 0;
}

// 2006-3-25: a naive implementation of background fetching, may need improvement in the future
void FeedFetcher::WorkerThreadProc()
{
	int nFeedToFetch = 0;
	while (m_bRunning) {
		while(!m_ToFetchFeeds.empty()){
			EnterCriticalSection(&m_cs);
			nFeedToFetch = m_ToFetchFeeds.front();
			m_ToFetchFeeds.pop();
			LeaveCriticalSection(&m_cs);			
			RunFetchAFeed(nFeedToFetch);			
		}
		Sleep(50);
	}
}
